'use strict';

// TODO move to appropriate module
function Animation(animationId) {
    this.id = animationId;
    this.imagePath = "images/unit-sprites/" + animationId;
}

var FAKE_ANIMATION_DELAY = 600;

function renderAnimation (animation, data, image){
    var div = $('<div class="animation-frame"></div>');
    div.css({
        'background-image' : 'url(' + animation.imagePath + '/' + image + '.png)',
        'width' : data.width + 'px',
        'height' : data.height + 'px'
    });
    return div;
};

Animation.prototype.renderStandingCharacter = function () {
    return renderAnimation(this, this.data.stand, 'stand');
};

Animation.prototype.renderIdleCharacter = function() {
    return renderAnimation(this.data.idle, 'idle');
};

Animation.prototype.hasIdleAnimation = function(){
    return !!this.data.idle;
};

Animation.prototype.hasMoveAnimation = function(){
    return !!this.data.walk;
};

Animation.prototype.hasAttackAnimation = function(){
    return !!this.data.attack;
};

Animation.prototype.stopAnimation = function(){
    if (this.idleAnimationTimeout)
        clearTimeout(this.idleAnimationTimeout);
    if (this.moveAnimationTimeout){
        clearTimeout(this.moveAnimationTimeout);
    }
    if (this.attackAnimationTimeout){
        clearTimeout(this.attackAnimationTimeout);
    }
};


Animation.prototype.startAttackAnimation = function(container, direction, character, callback) {
    var animation = this;
    if (animation.hasAttackAnimation()) {
        // TODO attack animation
        callback();
    } else {
        // fallback attack animation
        animation.attackAnimationTimeout = setTimeout(function() {
            var stand = animation.renderStandingCharacter();
            container.html(stand);

            // determine position
            var position = stand.position();
            var originalPosition = angular.copy(position);
            // correction for left align
            // XXX position.left = position.left.roundTo(50);
            var offset = 25;
            if (direction == 'left') {
                position.left -= offset;
            } else if (direction == 'right') {
                position.left += offset;
            } else if (direction == 'up') {
                position.top -= offset;
            } else if (direction == 'down') {
                position.top += offset;
            }

            // determine facing
            if (character.facing == 'left' && direction == 'right') {
                container.removeClass('flipped');
            }
            if (direction == 'left') {
                container.addClass('flipped');
                position.left = -1 * position.left;
            }

            stand.css(position);

            animation.attackAnimationTimeout = setTimeout(function() {
                stand.css(originalPosition);
                callback();
            }, FAKE_ANIMATION_DELAY);
        }, FAKE_ANIMATION_DELAY);
    }
};

Animation.prototype.startMoveAnimation = function(container, path, character, callback){

    function nextFakeMoveFrame(){
        var direction = path[counter];

        // determine position
        var position = stand.position();
        // correction for left align
        position.left = position.left.roundTo(50);
        if (direction == 'left') {
            position.left -= 50;
        } else if (direction == 'right') {
            position.left += 50;
        } else if (direction == 'up') {
            position.top -= 50;
        } else if (direction == 'down') {
            position.top += 50;
        }

        // determine facing
        if (previousFacing == 'left' && direction == 'right'){
            container.removeClass('flipped');
            previousFacing = direction;
        }
        if (previousFacing== 'left' || direction == 'left'){
            container.addClass('flipped');
            previousFacing = 'left';
            position.left = -1 * position.left;
        }

        stand.css(position);

        counter++;

        if (counter == path.length){
            character.facing = previousFacing;
            // animation ended
            callback();
        }else {
            animation.moveAnimationTimeout = setTimeout(nextFakeMoveFrame, FAKE_ANIMATION_DELAY);
        }
    }

    var animation = this;
    if (this.hasMoveAnimation()){
        // TODO move animation
        callback();
    } else {
        // fallback move animation
        var stand = this.renderStandingCharacter();
        container.html(stand);
        var counter = 0;
        var previousFacing = character.facing;
        nextFakeMoveFrame();


    }
};

Animation.prototype.startIdleAnimation = function(container, callback){
    var animation = this;

    var idleDiv = animation.renderIdleCharacter();
    container.html(idleDiv);

    var counter = 0;
    animation.idleAnimationTimeout = null;
    nextIdleFrame();

    function nextIdleFrame() {

        var positionX = counter * animation.data.idle.width;
        if (positionX > 0) {
            container.find('.animation-frame').css({
                'background-position-x' : '-' + counter * animation.data.idle.width + "px"
            });
        }

        counter++;

        // animation ended
        if (counter > animation.data.idle.frames) {
            container.find('.animation-frame').css({
                'background-position-x' : "0px"
            });
            callback();
            return;
        }

        animation.idleAnimationTimeout = setTimeout(function() {
            nextIdleFrame();
        }, 150);
    }
};

/* Services */

angular.module('ender.game.services', [ 'ngResource', 'module.ender.game.character.feats' ])
    .factory('gameStateService', function factoryFunction($location, featRepository, itemRepository, animationRepository) {

        var currentGame = {
            character: null
        };

        function fromCharacterClass(characterClass) {
            var character = new Ender.Game.Character(characterClass);
            angular.extend(character, characterClass);

            character.className = undefined; // e.g. "Hobbit"
            character.universe = undefined; // e.g. "lotr"

            character.gold = characterClass.gold;
            character.inventory = itemRepository.getInventoryByItemIdsInInventory(characterClass.inventory);
            character.feats = featRepository.getFeatsByIds(characterClass.feats);

            character.unlockedShops = angular.copy(characterClass.startingVendors);
            character.unlockedTrainers = angular.copy(characterClass.startingTrainers);

            character.bonus = {
                save: {
                    will: 0,
                    fortitude: 0,
                    reflex: 0,
                    all: 0
                },
                attack: [],
                damage: [],
                evasion: {
                    stackable: {
                        dodge: 0
                    },
                    unstackable: {

                    }
                }
            };

            character.proficiencies = {
                weapon: {},
                armor: {},
                shield: {}
            };

            character.animation = animationRepository.getAnimationById(characterClass.animation);

            return character;
        }

        return {
            startGame: function (characterClass) {
                currentGame.character = fromCharacterClass(characterClass);

                $location.path('/arena').search({ arenaId: 'concrete-yard'});
            },
            getPlayerCharacter: function () {
                // TODO temporary
                if (!currentGame.character)
                    currentGame.character = fromCharacterClass({
                        "id": "test-character",
                        "name": "Test Character",
                        "image": "placeholder.png",
                        "icon": "todo-icon.png",
                        "description": "test description",

                        "animation": "heroes3-crusader",

                        "attributes": {
                            "strength": 6,
                            "dexterity": 12,
                            "constitution": 8,
                            "intelligence": 10,
                            "wisdom": 12,
                            "charisma": 6
                        },

                        "skills": {
                            "appraise": 0,
                            "bluff": 0,
                            "diplomacy": 0
                        },

                        "feats": [ "fortitude_save_bonus", "reflex_save_bonus", "strong_back", "extra_loot", "skill_appraise_bluff", "skill_diplomacy_bluff" ],
                        "inventory": {
                            "mainHand": "steel-longsword",
                            "sideArm": "steel-shortsword",
                            "offHand": "steel-round-shield",
                            "head": "steel-full-helm",
                            "back": "green-cape"
                        },

                        "gold" : 10,

                        "startingVendors": [ "test-vendor" ],
                        "startingTrainers": [ "test-trainer" ]
                    });
                return currentGame.character;
            }
        }
    })
    .factory('shopRepository', function factoryFunction($resource, $q) {
        var resource = $resource('data/vendors.json');
        var deferred = $q.defer();
        var shopsResource = resource.get(function () {
            deferred.resolve();
        });

        return {
            getShopsByIds: function (shopIdList) {
                var shops = [];

                deferred.promise.then(function () {
                    for (var i = 0; i < shopIdList.length; i++) {
                        var shopId = shopIdList[i];
                        shops.push(shopsResource[shopId]);
                    }
                });

                return shops;
            }
        }
    })
    .factory('animationRepository', function factoryFunction($resource, $q) {
        var resource = $resource('data/animations.json');
        var deferred = $q.defer();
        var animationsResource = resource.get(function () {
            deferred.resolve();
        });

        return {
            getAnimationById: function (animationId) {
                var animation = new Animation(animationId);
                deferred.promise.then(function () {
                    animation.data = animationsResource[animationId];
                });
                return animation;
            },
            promise : deferred.promise
        }
    })
    .factory('itemRepository', function factoryFunction($resource, $q) {
        var resource = $resource('data/items.json');
        var deferred = $q.defer();
        var itemsResource = resource.get(function () {
            deferred.resolve();
        });

        return {
            getInventoryByItemIdsInInventory: function (inventoryWithIds) {
                var inventory = {};

                deferred.promise.then(function () {
                    for (var slot in inventoryWithIds) {
                        var itemId = inventoryWithIds[slot];
                        var item = itemsResource[itemId];
                        inventory[slot] = item;
                    }
                });

                return inventory;
            }
        }
    });
